/*!
  @file   MatrixTypes.hpp
  @author Jared Marsau
  @author Hamza M. Hutchinson
  @date   03/01/2009
  @brief  
    This header file outlines the interface for both 3x3 and 4x4 matrix types.
*/

#ifndef MATRIX_TYPES_HPP
#define MATRIX_TYPES_HPP

#include "MathUtility.hpp"  //MATH_EPSILON
#include "VectorTypes.hpp"  //Vector3D & Vector4D

namespace VectorTypes
{
  /*!
  @brief
    This defines a 3x3 matrix, its operators, and methods.
  */
  struct Matrix3D
  {
    //Constructors
    Matrix3D();
    Matrix3D(const float* arrayOfNineFloats);
    Matrix3D(const Vector3D &row0,
             const Vector3D &row1,
             const Vector3D &row2);
    Matrix3D(float m00, float m01, float m02,
             float m10, float m11, float m12,
             float m20, float m21,float  m22);

    //Assignment operators
    Matrix3D& operator =  (const Matrix3D& rhs);
    Matrix3D& operator += (const Matrix3D& rhs);
    Matrix3D& operator -= (const Matrix3D& rhs);
    Matrix3D& operator *= (float rhs);
    Matrix3D& operator /= (float rhs);

    //Access operators
    Vector3D&       operator [] (unsigned row);
    const Vector3D& operator [] (unsigned row) const;

    //Binary operators
    Matrix3D operator + (const Matrix3D& rhs) const;
    Matrix3D operator - (const Matrix3D& rhs) const;
    Matrix3D operator * (const Matrix3D& rhs) const;
    Vector3D operator * (const Vector3D& rhs) const;
    Matrix3D operator * (float rhs)           const;
    Matrix3D operator / (float rhs)           const;

    bool operator == (const Matrix3D& rhs) const;
    bool operator != (const Matrix3D& rhs) const;

    //Methods
    void         Set           (float m00, float m01, float m02,
                                float m10, float m11, float m12,
                                float m20, float m21,float  m22);
    void         Set           (const Vector3D &row0,
                                const Vector3D &row1,
                                const Vector3D &row2);
    void         Set           (const Matrix3D& source);
    void         Invert        ();
    void         Transpose     ();

    float        Determinant   ()                                       const;
    Matrix3D     Inverse       ()                                       const;
    Matrix3D     Transposed    ()                                       const;
    bool         IsInvertable  (float tolerance = MathUtility::MATH_EPSILON) const;

    Vector3D     Row           (unsigned row)                           const;
    Vector3D     Column        (unsigned column)                        const;

    //Members
    Vector3D m_Rows[3];
  };
  
  Matrix3D operator * (float lhs, const Matrix3D& rhs);
  
  /*!
  @brief
    This defines a 4x4 matrix, its operators, and methods.
  */
  struct Matrix4D
  {
    //Constructors
    Matrix4D();
    Matrix4D(const float* arrayOfSixteenFloats);
    Matrix4D(const Vector4D &row0,
             const Vector4D &row1,
             const Vector4D &row2,
             const Vector4D &row3);
    Matrix4D(float m00, float m01, float m02, float m03,
             float m10, float m11, float m12, float m13,
             float m20, float m21,float  m22, float m23,
             float m30, float m31, float m32, float m33);

    //Assignment operators
    Matrix4D& operator =  (const Matrix4D& rhs);
    Matrix4D& operator += (const Matrix4D& rhs);
    Matrix4D& operator -= (const Matrix4D& rhs);
    Matrix4D& operator *= (float rhs);
    Matrix4D& operator /= (float rhs);

    //Access operators
    Vector4D&       operator [] (unsigned row);
    const Vector4D& operator [] (unsigned row) const;

    //Binary operators
    Matrix4D operator + (const Matrix4D& rhs) const;
    Matrix4D operator - (const Matrix4D& rhs) const;
    Matrix4D operator * (const Matrix4D& rhs) const;
    Vector4D operator * (const Vector4D& rhs) const;
    Matrix4D operator * (float rhs)           const;
    Matrix4D operator / (float rhs)           const;

    bool operator == (const Matrix4D& rhs) const;
    bool operator != (const Matrix4D& rhs) const;

    //Methods
    void         Set           (float m00, float m01, float m02, float m03,
                                float m10, float m11, float m12, float m13,
                                float m20, float m21,float  m22, float m23,
                                float m30, float m31, float m32, float m33);
    void         Set           (const Vector4D &row0,
                                const Vector4D &row1,
                                const Vector4D &row2,
                                const Vector4D &row3);
    void         Set           (const Matrix4D& source);
    void         Invert        ();
    void         Transpose     ();

    float        Determinant   ()                                       const;
    Matrix4D     Inverse       ()                                       const;
    Matrix4D     Transposed    ()                                       const;
    bool         IsInvertable  (float tolerance = MathUtility::MATH_EPSILON) const;

    Vector4D     Row           (unsigned row)                           const;
    Vector4D     Column        (unsigned column)                        const;

    //Members
    Vector4D m_Rows[4];
  };
  
  Matrix4D operator * (float lhs, const Matrix4D& rhs);
  
}//namespace VectorTypes

#endif
